package chen.web.user;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.util.Assert;

import chen.web.DataSourceProvider;
import chen.web.MyContextProvider;

public class AccountManagerImpl implements AccountManager {

	private SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(DataSourceProvider.getDataSource());
	private static ObjectMapper objectMapper = new ObjectMapper();
	
	private RoleManager rm = null;
	public AccountManagerImpl(RoleManager rm){
		this.rm = rm;
	}
	
	private static final String SQL_4 = "select * from web_account where acc_id = ?";
	@Override
	public Account getAccount(int id) {
		// TODO Auto-generated method stub
		Account account = null;
		try{
			account = simpleJdbcTemplate.queryForObject(SQL_4, new AccountRowMapper(rm), id);		
		} catch(EmptyResultDataAccessException e){
			//do nothing
		}
		return account;
	}

	private static final String SQL_1 = "select * from web_account where acc_nickname = ?";
	@Override
	public Account getAccountByName(String nickname) {
		// TODO Auto-generated method stub
		if(nickname == null || nickname.length() == 0){
			throw new IllegalArgumentException();
		}
		Account account = null;
		try{
			account = simpleJdbcTemplate.queryForObject(SQL_1, new AccountRowMapper(rm), nickname);			
		}catch(EmptyResultDataAccessException e){
			//do nothing
		}
		return account;
	}

	private static final String SQL_8 = "update web_account set acc_nickname = ?, acc_password = ?, acc_email = ?, acc_flag = ?, role_Id = ?, acc_rank = ?, acc_extInfo = ? where acc_id = ?";
	@Override
	public void update(final Account account) {
		// TODO Auto-generated method stub
		ExtInfo extInfo = account.getExtInfo();
		String json = null;
		try {
			json = objectMapper.writeValueAsString(extInfo);
		} catch (JsonGenerationException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		} catch (JsonMappingException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
		simpleJdbcTemplate.update(SQL_8, account.getNickname(), account.getPassword().toString(), account.getEmail(), account.getFlag(), account.getRole().getId(), account.getRank(), json, account.getId());
	}

	private static final String SQL_2 = "insert into web_account(acc_nickname, acc_password, acc_email, acc_created, role_id) values(?, ?, ?, ?, ?)";
	@Override	
	public Account register(String nickname, String password, String email) throws NicknameAlreadyBeenRegisteredException, EmailAlreadyBeenRegisteredException {
		if(getAccountByName(nickname) != null){
			throw new NicknameAlreadyBeenRegisteredException();
		}
		if(getAccountByEmail(email) != null){
			throw new EmailAlreadyBeenRegisteredException();
		}
		Account account = new Account();
		account.setNickname(nickname);
		account.setPassword(new Password(password));
		account.setEmail(email);
		//设置账号为访客
		account.setRole(InternalRoleProvider.getGuestRole());
		
		simpleJdbcTemplate.update(SQL_2, account.getNickname(), account.getPassword().toString(), account.getEmail(), new Timestamp(System.currentTimeMillis()), account.getRole().getId());
		return getAccountByName(account.getNickname());
	}

	@Override
	public Account increaseRank(Account account, int increase) {
		// TODO Auto-generated method stub
		int rank = account.getRank();
		rank = rank + increase;
		account.setRank(rank);
		update(account);
		return account;
	}

	private static final String SQL_32 = "select count(*) from web_account";
	@Override
	public int totalAccount() {
		// TODO Auto-generated method stub
		int amount = simpleJdbcTemplate.queryForInt(SQL_32);
		return amount;
	}

	private static final String  SQL_33 = "update web_account set role_id = ? where role_id = ?";
	@Override
	public void mergeAccount(Role oldRole, Role newRole) {
		// TODO Auto-generated method stub
		simpleJdbcTemplate.update(SQL_33, newRole.getId(), oldRole.getId());
	}

	@Override
	public Account changeRole(Account account, Role role) {
		// TODO Auto-generated method stub
		account.setRole(role);
		update(account);
		return account;
	}
	
	private static final String SQL_6 = "select * from web_account where acc_email = ?";
	@Override
	public Account getAccountByEmail(String email) {
		// TODO Auto-generated method stub
		Account acc = null;
		try{
			acc = simpleJdbcTemplate.queryForObject(SQL_6, new AccountRowMapper(rm), email);	
		} catch(EmptyResultDataAccessException e){
			//do nothing
		}
		return acc;
	}
	
	@Override
	public Account changeEmail(Account account, String newEmail) throws EmailAlreadyBeenRegisteredException{
		// TODO Auto-generated method stub
		if(account.getEmail().equalsIgnoreCase(newEmail)){
			return account;
		}
		//邮箱已经被注册
		if(getAccountByEmail(newEmail) != null){
			throw new EmailAlreadyBeenRegisteredException();
		}
		account.setEmail(newEmail);
		update(account);
		return account;
	}
	

	@Override
	public Account changeEmail(String email, String password) throws InvalidPasswordException, EmailAlreadyBeenRegisteredException {
		// TODO Auto-generated method stub
		Account account = MyContextProvider.getMyContext().getAccount();
		if(account.getPassword().check(password)){
			return changeEmail(account, email);
		}
		throw new InvalidPasswordException();
	}

	@Override
	public Account changePassword(String newPassword, String oldPassword) throws InvalidPasswordException {
		// TODO Auto-generated method stub
		Account account = MyContextProvider.getMyContext().getAccount();
		if(account.getPassword().check(oldPassword)){
			return changePassword(account, newPassword);
		}
		throw new InvalidPasswordException();
	}
	
	@Override
	public Account changePassword(Account account, String newPassword) {
		// TODO Auto-generated method stub
		Assert.hasLength(newPassword);
		Password password = new Password(newPassword);
		account.setPassword(password);
		update(account);
		return account;
	}
	
	private static final String SQL_3 = "delete from web_account where acc_id = ?";
	@Override
	public void deleteAccount(final Account account) {
		// TODO Auto-generated method stub
		Integer id = account.getId();
		if(id == null || id == 0){
			throw new IllegalArgumentException();
		}
		simpleJdbcTemplate.update(SQL_3, account.getId());
	}
	
	@Override
	public List<Account> getAccount(List<Integer> ids) {
		// TODO Auto-generated method stub
		if(ids == null || ids.size() == 0){
			return new ArrayList<Account>(0);
		}
		StringBuffer sql = new StringBuffer();
		sql.append("select * from web_account where acc_id in (");
		for(int id : ids){
			sql.append(id).append(",");
		}
		sql.deleteCharAt(sql.length()-1)
			.append(")");
		List<Account> list = simpleJdbcTemplate.query(sql.toString(), new AccountRowMapper(rm));
	
		//保证数据的大小、顺序一致
		List<Account> result = new ArrayList<Account>(ids.size());
		for(int i=0; i<ids.size(); i++){
			int id = ids.get(i);
			for(int j=0; j<list.size(); j++){
				Account acc = list.get(j);
				if(id == acc.getId()){
					result.add(acc);
				}
			}
			//id没有对应的结果
			if(result.size() == i){
				result.add(null);
			}
		}
		
		return result;
	}
	
	private static final class AccountRowMapper implements RowMapper<Account>{
		private RoleManager rm;
		AccountRowMapper(RoleManager rm){
			this.rm = rm;
		}
		@Override
		public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
			// TODO Auto-generated method stub
			Account acc = new Account(rs.getInt("acc_id"));
			acc.setNickname(rs.getString("acc_nickname"));
			acc.setEmail(rs.getString("acc_email"));
			acc.setFlag(rs.getInt("acc_flag"));
			acc.setCreated(rs.getTimestamp("acc_created"));
			acc.setRole(rm.getRole(rs.getInt("role_id")));
			acc.setRank(rs.getInt("acc_rank"));
			acc.setOnlineSeconds(rs.getInt("acc_onlineSeconds"));
			acc.setLastOnline(rs.getTimestamp("acc_lastOnline"));
			acc.setLastOffline(rs.getTimestamp("acc_lastOffline"));
			
			String passwordString = rs.getString("acc_password");
			if(passwordString != null){
				String[] ss = passwordString.split(":");
				if(ss.length != 2){
					throw new IllegalArgumentException("数据库中帐号密码格式不匹配");
				}
				acc.setPassword(new Password(ss[0], ss[1]));
			}
			
			String extInfoStr = rs.getString("acc_extInfo");
			if(extInfoStr != null && extInfoStr.length() != 0){
				try {
					ExtInfo extInfo = objectMapper.readValue(extInfoStr, ExtInfo.class);
					acc.setExtInfo(extInfo);
				} catch (JsonParseException e) {
					// TODO Auto-generated catch block
					throw new RuntimeException(e);
				} catch (JsonMappingException e) {
					// TODO Auto-generated catch block
					throw new RuntimeException(e);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					throw new RuntimeException(e);
				}
				
			}
			return acc;
		}
	}
}
